home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Internet Info 1994 March
/
Internet Info CD-ROM (Walnut Creek) (March 1994).iso
/
networking
/
ip
/
ka9q
/
src.arc
/
NR3.C
< prev
next >
Wrap
C/C++ Source or Header
|
1989-08-19
|
28KB
|
1,048 lines
/* net/rom level 3 low level processing
* Copyright 1989 by Daniel M. Frank, W9NK. Permission granted for
* non-commercial distribution only.
*/
#include <stdio.h>
#include <ctype.h>
#include "global.h"
#include "mbuf.h"
#include "iface.h"
#include "timer.h"
#include "arp.h"
#include "slip.h"
#include "ax25.h"
#include "netrom.h"
#include "nr4.h"
#include "lapb.h"
#include "socket.h"
#include "trace.h"
#include "ip.h"
static int accept_bc __ARGS((struct ax25_addr *addr,unsigned ifnum));
static struct nr_bind *find_best __ARGS((struct nr_bind *list,unsigned obso));
static struct nr_bind *find_binding __ARGS((struct nr_bind *list,struct nrnbr_tab *neighbor));
static struct nrnbr_tab *find_nrnbr __ARGS((struct ax25_addr *, unsigned));
static struct nrnf_tab *find_nrnf __ARGS((struct ax25_addr *, unsigned));
static struct nr_bind *find_worst __ARGS((struct nr_bind *list));
static int ismycall __ARGS((struct ax25_addr *addr));
#ifdef notdef
static char *nr_getroute __ARGS((struct ax25_addr *));
#endif
static int nr_send __ARGS((struct mbuf *bp,struct iface *iface,int32 gateway,int prec,
int del,int tput,int rel));
static void nr3arp __ARGS((void));
static struct raw_nr *Raw_nr;
/* Nodes message broadcast address: "NODES" in shifted ASCII */
struct ax25_addr Nr_nodebc = {
'N'<<1, 'O'<<1, 'D'<<1, 'E'<<1, 'S'<<1, ' '<<1,
('0'<<1) | E
} ;
struct nriface Nrifaces[NRNUMIFACE] ;
unsigned Nr_numiface ;
struct nrnbr_tab *Nrnbr_tab[NRNUMCHAINS] ;
struct nrroute_tab *Nrroute_tab[NRNUMCHAINS] ;
struct nrnf_tab *Nrnf_tab[NRNUMCHAINS] ;
unsigned Nr_nfmode = NRNF_NOFILTER ;
unsigned short Nr_ttl = 64 ;
static unsigned Obso_init = 6 ;
static unsigned Obso_minbc = 5 ;
static unsigned Nr_maxroutes = 5 ;
static unsigned Nr_autofloor = 1 ;
int Nr_verbose = 0 ;
struct iface *Nr_iface ;
/* send a NET/ROM layer 3 datagram */
void
nr3output(dest, data)
struct ax25_addr *dest ;
struct mbuf *data ;
{
struct nr3hdr n3hdr ;
struct mbuf *n3b ;
ASSIGN(n3hdr.dest,*dest) ; /* copy destination field */
n3hdr.ttl = Nr_ttl ; /* time to live from initializer parm */
if ((n3b = htonnr3(&n3hdr)) == NULLBUF) {
free_p(data) ;
return ;
}
append(&n3b, data) ;
/* The null interface indicates that the packet needs to have */
/* an appropriate source address inserted by nr_route */
nr_route(n3b,NULLAX25) ;
}
/* send IP datagrams across a net/rom network connection */
int
nr_send(bp,iface,gateway,prec,del,tput,rel)
struct mbuf *bp ;
struct iface *iface ;
int32 gateway ;
int prec ;
int del ;
int tput ;
int rel ;
{
struct arp_tab *arp ;
dump(iface,IF_TRACE_OUT,TYPE_IP,bp);
if ((arp = arp_lookup(ARP_NETROM,gateway)) == NULLARP) {
free_p(bp) ; /* drop the packet if no route */
return -1;
}
nr_sendraw(arp->hw_addr, NRPROTO_IP, NRPROTO_IP, bp);
return 0;
}
/* Send arbitrary protocol data on top of a NET/ROM connection */
void
nr_sendraw(dest,family,proto,data)
struct ax25_addr *dest;
unsigned family;
unsigned proto;
struct mbuf *data;
{
struct mbuf *pbp ;
struct nr4hdr n4hdr ;
/* Create a "network extension" transport header */
n4hdr.opcode = NR4OPPID ;
n4hdr.u.pid.family = family;
n4hdr.u.pid.proto = proto;
if ((pbp = htonnr4(&n4hdr)) == NULLBUF) {
free_p(data) ;
return ;
}
append(&pbp,data) ; /* Append the data to that */
nr3output(dest, pbp) ; /* and pass off to level 3 code */
}
/* Arrange for receipt of raw NET/ROM datagrams */
struct raw_nr *
raw_nr(protocol)
char protocol;
{
register struct raw_nr *rp;
rp = (struct raw_nr *)calloc(1,sizeof(struct raw_nr));
rp->protocol = protocol;
rp->next = Raw_nr;
if(rp->next != NULLRNR)
rp->next->prev = rp;
Raw_nr = rp;
return rp;
}
/* Free a raw NET/ROM descriptor */
void
del_rnr(rpp)
struct raw_nr *rpp;
{
register struct raw_nr *rp;
/* Do sanity check on arg */
for(rp = Raw_nr;rp != NULLRNR;rp = rp->next)
if(rp == rpp)
break;
if(rp == NULLRNR)
return; /* Doesn't exist */
/* Unlink */
if(rp->prev != NULLRNR)
rp->prev->next = rp->next;
else
Raw_nr = rp->next;
if(rp->next != NULLRNR)
rp->next->prev = rp->prev;
/* Free resources */
free_q(&rp->rcvq);
free((char *)rp);
}
/* Figure out if a call is assigned to one of my net/rom
* interfaces.
*/
static int
ismycall(addr)
struct ax25_addr *addr ;
{
register int i ;
int found = 0 ;
for (i = 0 ; i < Nr_numiface ; i++)
if (addreq((struct ax25_addr *)(Nrifaces[i].iface->hwaddr),
addr)) {
found = 1 ;
break ;
}
return found ;
}
/* Route net/rom network layer packets.
*/
void
nr_route(bp, iaxp)
struct mbuf *bp ; /* network packet */
struct ax25_cb *iaxp ; /* incoming ax25 control block */
{
struct nr3hdr n3hdr ;
struct nr4hdr n4hdr ;
struct ax25_cb *axp;
struct ax25 naxhdr ;
struct ax25_addr neighbor, from ;
struct mbuf *hbp, *pbp;
struct raw_nr *rnr;
register struct nrnbr_tab *np ;
register struct nrroute_tab *rp ;
register struct nr_bind *bindp;
struct iface *iface ;
unsigned ifnum ;
if (ntohnr3(&n3hdr,&bp) == -1) {
free_p(bp) ;
return ;
}
/* If this isn't an internally generated network packet,
* give the router a chance to record a route back to the
* sender, in case they aren't in the local node's routing
* table yet.
*/
if (iaxp != NULLAX25 && ax_lookup(&iaxp->remote) != NULLAXR) {
/* find the interface number */
for (ifnum = 0 ; ifnum < Nr_numiface ; ifnum++)
if (iaxp->iface == Nrifaces[ifnum].iface)
break ;
if (ifnum == Nr_numiface) { /* Not a net/rom interface! */
free_p(bp) ;
return ;
}
from = iaxp->remote ;
from.ssid |= E ;
/* Add (possibly) a zero-quality recorded route via */
/* the neighbor from which this packet was received */
/* Note that this doesn't work with digipeated neighbors. */
(void) nr_routeadd(" ",&n3hdr.source,ifnum,0,
(char *)&from,0,1) ;
}
/* A packet from me, to me, can only be one thing: */
/* a horrible routing loop. This will probably result */
/* from a bad manual ARP entry, but we should fix these */
/* obscure errors as we find them. */
if (ismycall(&n3hdr.dest)) {
/* Toss if from me, or if we can't read the header */
if (iaxp == NULLAX25 || ntohnr4(&n4hdr,&bp) == -1){
free_p(bp) ;
} else if((n4hdr.opcode & NR4OPCODE) == NR4OPPID){
for(rnr = Raw_nr;rnr!=NULLRNR;rnr = rnr->next){
if(rnr->protocol!=n4hdr.u.pid.family ||
rnr->protocol != n4hdr.u.pid.proto)
continue;
/* Duplicate the data portion, and put the
* level 3 header back on
*/
dup_p(&pbp,bp,0,len_mbuf(bp));
if(pbp != NULLBUF &&
(hbp = htonnr3(&n3hdr)) != NULLBUF){
append(&hbp,pbp);
enqueue(&rnr->rcvq,hbp);
} else {
free_p(pbp);
free_p(hbp);
}
}
/* IP does not use a NET/ROM level 3 socket */
if (n4hdr.u.pid.family == NRPROTO_IP
&& n4hdr.u.pid.proto == NRPROTO_IP)
ip_route(bp,0) ;
else /* we don't do this proto */
free_p(bp) ;
} else {
/* Must be net/rom transport: */
nr4input(&n4hdr,bp) ;
}
return ;
}
if ((rp = find_nrroute(&n3hdr.dest)) == NULLNRRTAB) {
/* no route, drop the packet */
free_p(bp) ;
return ;
}
if ((bindp = find_best(rp->routes,1)) == NULLNRBIND) {
/* This shouldn't happen yet, but might if we add */
/* dead route detection */
free_p(bp) ;
return ;
}
np = bindp->via ;
memcpy(neighbor.call,np->call,ALEN) ;
neighbor.ssid = np->call[ALEN] ;
iface = Nrifaces[np->iface].iface ;
/* Now check to see if iaxp is null. That is */
/* a signal that the packet originates here, */
/* so we need to insert the callsign of the appropriate */
/* interface */
if (iaxp == NULLAX25)
memcpy(&n3hdr.source,iface->hwaddr,AXALEN) ;
/* Make sure there is a connection to the neighbor */
if ((axp = find_ax25(&neighbor)) == NULLAX25 ||
(axp->state != CONNECTED && axp->state != RECOVERY)) {
/* Open a new connection or reinitialize old one */
/* hwaddr has been advanced to point to neighbor + digis */
atohax25(&naxhdr, np->call, (struct ax25_addr *)iface->hwaddr) ;
axp = open_ax25(iface,&Mycall,&naxhdr.dest, AX_ACTIVE, Axwindow, s_arcall, s_atcall, s_ascall,-1) ;
if (axp == NULLAX25) {
free_p(bp) ;
return ;
}
}
if (--n3hdr.ttl == 0) { /* the packet's time to live is over! */
free_p(bp) ;
return ;
}
/* now format network header */
if ((pbp = htonnr3(&n3hdr)) == NULLBUF) {
free_p(bp) ;
return ;
}
append(&pbp,bp) ; /* append data to header */
/* put AX.25 PID on front */
if((bp = pushdown(pbp,1)) == NULLBUF){
free_p(pbp) ;
return ;
}
bp->data[0] = PID_NETROM ;
if((pbp = segmenter(bp,axp->paclen)) == NULLBUF){
free_p(bp);
return;
}
send_ax25(axp,pbp,-1) ; /* pass it off to ax25 code */
}
/* Perform a nodes broadcast on interface # ifno in the net/rom
* interface table.
*/
void
nr_bcnodes(ifno)
unsigned ifno ;
{
struct mbuf *hbp, *dbp, *savehdr ;
struct nrroute_tab *rp ;
struct nrnbr_tab *np ;
struct nr_bind * bp ;
struct nr3dest nrdest ;
int i, didsend = 0, numdest = 0 ;
register char *cp ;
struct iface *axif = Nrifaces[ifno].iface ;
/* prepare the header */
if ((hbp = alloc_mbuf(NR3NODEHL)) == NULLBUF)
return ;
hbp->cnt = NR3NODEHL ;
*hbp->data = NR3NODESIG ;
memcpy(hbp->data+1,Nrifaces[ifno].alias,ALEN) ;
/* Some people don't want to advertise any routes; they
* just want to be a terminal node. In that case we just
* want to send our call and alias and be done with it.
*/
if (!Nr_verbose) {
(*axif->output)(axif, (char *)&Nr_nodebc, axif->hwaddr,
PID_NETROM, hbp) ; /* send it */
return ;
}
/* make a copy of the header in case we need to send more than */
/* one packet */
savehdr = copy_p(hbp,NR3NODEHL) ;
/* now scan through the routing table, finding the best routes */
/* and their neighbors. create destination subpackets and append */
/* them to the header */
for (i = 0 ; i < NRNUMCHAINS ; i++) {
for (rp = Nrroute_tab[i] ; rp != NULLNRRTAB ; rp = rp->next) {
/* look for best, non-obsolescent route */
if ((bp = find_best(rp->routes,0)) == NULLNRBIND)
continue ; /* no non-obsolescent routes found */
if (bp->quality == 0) /* this is a loopback route */
continue ; /* we never broadcast these */
np = bp->via ;
/* insert best neighbor */
memcpy(nrdest.neighbor.call,np->call,ALEN) ;
nrdest.neighbor.ssid = np->call[ALEN] ;
/* insert destination from route table */
nrdest.dest = rp->call ;
/* insert alias from route table */
strcpy(nrdest.alias,rp->alias) ;
/* insert quality from binding */
nrdest.quality = bp->quality ;
/* create a network format destination subpacket */
if ((dbp = htonnrdest(&nrdest)) == NULLBUF) {
free_p(hbp) ; /* drop the whole idea ... */
free_p(savehdr) ;
return ;
}
append(&hbp,dbp) ; /* append to header and others */
/* see if we have appended as many destinations */
/* as we can fit into a single broadcast. If we */
/* have, go ahead and send them out. */
if (++numdest == NRDESTPERPACK) { /* filled it up */
didsend = 1 ; /* indicate that we did broadcast */
numdest = 0 ; /* reset the destination counter */
(*axif->output)(axif, (char *)&Nr_nodebc, axif->hwaddr,
PID_NETROM,
hbp) ; /* send it */
hbp = copy_p(savehdr,NR3NODEHL) ; /* new header */
}
}
}
/* Now, here is something totally weird. If our interfaces */
/* have different callsigns than this one, advertise a very */
/* high quality route to them. Is this a good idea? I don't */
/* know. However, it allows us to simulate a bunch of net/roms */
/* hooked together with a diode matrix coupler. */
for (i = 0 ; i < Nr_numiface ; i++) {
if (i == ifno)
continue ; /* don't bother with ours */
cp = Nrifaces[i].iface->hwaddr ;
if (!addreq((struct ax25_addr *)axif->hwaddr,cp)) {
/* both destination and neighbor address */
memcpy(&nrdest.dest,cp,AXALEN) ;
memcpy(&nrdest.neighbor,cp,AXALEN) ;
/* alias of the interface */
strcpy(nrdest.alias,Nrifaces[i].alias) ;
/* and the very highest quality */
nrdest.quality = 255 ;
/* create a network format destination subpacket */
if ((dbp = htonnrdest(&nrdest)) == NULLBUF) {
free_p(hbp) ; /* drop the whole idea ... */
free_p(savehdr) ;
return ;
}
append(&hbp,dbp) ; /* append to header and others */
if (++numdest == NRDESTPERPACK) { /* filled it up */
didsend = 1 ; /* indicate that we did broadcast */
numdest = 0 ; /* reset the destination counter */
(*axif->output)(axif, (char *)&Nr_nodebc, axif->hwaddr,
PID_NETROM,
hbp) ; /* send it */
hbp = copy_p(savehdr,NR3NODEHL) ; /* new header */
}
}
}
/* If we have a partly filled packet left over, or we never */
/* sent one at all, we broadcast: */
if (!didsend || numdest > 0)
(*axif->output)(axif, (char *)&Nr_nodebc, axif->hwaddr,
PID_NETROM, hbp) ;
free_p(savehdr) ; /* free the header copy */
}
/* initialize fake arp entry for netrom */
static void
nr3arp()
{
arp_init(ARP_NETROM,AXALEN,0,0,0,NULLCHAR,psax25,setpath) ;
}
/* attach the net/rom interface. no parms for now. */
int
nr_attach(argc,argv,p)
int argc ;
char *argv[] ;
void *p;
{
if (Nr_iface != (struct iface *)0) {
printf("netrom interface already attached\n") ;
return -1 ;
}
nr3arp() ;
Nr_iface = (struct iface *)calloc(1,sizeof(struct iface)) ;
Nr_iface->name = "netrom" ;
Nr_iface->mtu = NR4MAXINFO ;
Nr_iface->send = nr_send ;
Nr_iface->next = Ifaces ;
Ifaces = Nr_iface ;
ASSIGN(Nr4user,Mycall);
return 0 ;
}
/* This function checks an ax.25 address and interface number against
* the filter table and mode, and returns 1 if the address is to be
* accepted, and 0 if it is to be filtered out.
*/
static int
accept_bc(addr,ifnum)
struct ax25_addr *addr ;
unsigned ifnum ;
{
struct nrnf_tab *fp ;
if (Nr_nfmode == NRNF_NOFILTER) /* no filtering in effect */
return 1 ;
fp = find_nrnf(addr,ifnum) ; /* look it up */
if ((fp != NULLNRNFTAB && Nr_nfmode == NRNF_ACCEPT)
|| (fp == NULLNRNFTAB && Nr_nfmode == NRNF_REJECT))
return 1 ;
else
return 0 ;
}
/* receive and process node broadcasts. */
void
nr_nodercv(iface,source,bp)
struct iface *iface ;
struct ax25_addr *source ;
struct mbuf *bp ;
{
register int ifnum ;
char bcalias[7] ;
struct nr3dest ds ;
char sbuf[AXALEN*3] ;
/* First, see if this is even a net/rom interface: */
for (ifnum = 0 ; ifnum < Nr_numiface ; ifnum++)
if (iface == Nrifaces[ifnum].iface)
break ;
if (ifnum == Nr_numiface) { /* not in the interface table */
free_p(bp) ;
return ;
}
if (!accept_bc(source,ifnum)) { /* check against filter */
free_p(bp) ;
return ;
}
/* See if it has a routing broadcast signature: */
if (uchar(pullchar(&bp)) != NR3NODESIG) {
free_p(bp) ;
return ;
}
/* now try to get the alias */
if (pullup(&bp,bcalias,ALEN) < ALEN) {
free_p(bp) ;
return ;
}
bcalias[ALEN] = '\0' ; /* null terminate */
/* copy source address and convert to arp format */
memcpy(sbuf,source->call,ALEN) ;
sbuf[ALEN] = (source->ssid | E) ; /* terminate */
/* enter the neighbor into our routing table */
if (nr_routeadd(bcalias,source,ifnum,Nrifaces[ifnum].quality,
sbuf, 0, 0) == -1) {
free_p(bp) ;
return ;
}
/* we've digested the header; now digest the actual */
/* routing information */
while (ntohnrdest(&ds,&bp) != -1) {
/* ignore routes to me! */
if (ismycall(&ds.dest))
continue ;
/* ignore routes below the minimum quality threshhold */
if (ds.quality < Nr_autofloor)
continue ;
/* set loopback paths to 0 quality */
if (ismycall(&ds.neighbor))
ds.quality = 0 ;
else
ds.quality = ((ds.quality * Nrifaces[ifnum].quality + 128)
/ 256) & 0xff ;
if (nr_routeadd(ds.alias,&ds.dest,ifnum,ds.quality,sbuf,0,0)
== -1)
break ;
}
free_p(bp) ; /* This will free the mbuf if anything fails above */
}
/* The following are utilities for manipulating the routing table */
/* hash function for callsigns. Look familiar? */
int16
nrhash(s)
struct ax25_addr *s ;
{
register char x ;
register int i ;
register char *cp ;
x = 0 ;
cp = s->call ;
for (i = ALEN ; i !=0 ; i--)
x ^= *cp++ & 0xfe ;
x ^= s->ssid & SSID ;
return uchar(x) % NRNUMCHAINS ;
}
/* Find a neighbor table entry. Neighbors are determined by
* their callsign and the interface number. This takes care
* of the case where the same switch or hosts uses the same
* callsign on two different channels. This isn't done by
* net/rom, but it might be done by stations running *our*
* software.
*/
static struct nrnbr_tab *
find_nrnbr(addr,ifnum)
register struct ax25_addr *addr ;
unsigned ifnum ;
{
int16 hashval ;
register struct nrnbr_tab *np ;
char i_state ;
struct ax25_addr ncall ;
/* Find appropriate hash chain */
hashval = nrhash(addr) ;
/* search hash chain */
i_state = dirps() ;
for (np = Nrnbr_tab[hashval] ; np != NULLNTAB ; np = np->next) {
memcpy(ncall.call,np->call,ALEN) ; /* convert first in */
ncall.ssid = np->call[ALEN] ; /* list to ax25 address format */
if (addreq(&ncall,addr) && np->iface == ifnum) {
restore(i_state) ;
return np ;
}
}
restore(i_state) ;
return NULLNTAB ;
}
/* Find a route table entry */
struct nrroute_tab *
find_nrroute(addr)
register struct ax25_addr *addr ;
{
int16 hashval ;
register struct nrroute_tab *rp ;
char i_state ;
/* Find appropriate hash chain */
hashval = nrhash(addr) ;
/* search hash chain */
i_state = dirps() ;
for (rp = Nrroute_tab[hashval] ; rp != NULLNRRTAB ; rp = rp->next) {
if (addreq(&rp->call,addr)) {
restore(i_state) ;
return rp ;
}
}
restore(i_state) ;
return NULLNRRTAB ;
}
/* Try to find the AX.25 address of a node with the given alias. Return */
/* a pointer to the AX.25 address if found, otherwise NULLAXADDR. The alias */
/* should be a six character, blank-padded, upper-case string. */
struct ax25_addr *
find_nralias(alias)
char *alias ;
{
int i ;
register struct nrroute_tab *rp ;
/* Since the route entries are hashed by ax.25 address, we'll */
/* have to search all the chains */
for (i = 0 ; i < NRNUMCHAINS ; i++)
for (rp = Nrroute_tab[i] ; rp != NULLNRRTAB ; rp = rp->next)
if (strncmp(alias, rp->alias, 6) == 0)
return &rp->call ;
/* If we get to here, we're out of luck */
return NULLAXADDR ;
}
/* Find a binding in a list by its neighbor structure's address */
static struct nr_bind *
find_binding(list,neighbor)
struct nr_bind *list ;
register struct nrnbr_tab *neighbor ;
{
register struct nr_bind *bp ;
for(bp = list ; bp != NULLNRBIND ; bp = bp->next)
if (bp->via == neighbor)
return bp ;
return NULLNRBIND ;
}
/* Find the worst quality non-permanent binding in a list */
static
struct nr_bind *
find_worst(list)
struct nr_bind *list ;
{
register struct nr_bind *bp ;
struct nr_bind *worst = NULLNRBIND ;
unsigned minqual = 1000 ; /* infinity */
for (bp = list ; bp != NULLNRBIND ; bp = bp->next)
if (!(bp->flags & NRB_PERMANENT) && bp->quality < minqual) {
worst = bp ;
minqual = bp->quality ;
}
return worst ;
}
/* Find the best binding of any sort in a list. If obso is 1,
* include entries below the obsolescence threshhold in the
* search (used when this is called for routing broadcasts).
* If it is 0, routes below the threshhold are treated as
* though they don't exist.
*/
static
struct nr_bind *
find_best(list,obso)
struct nr_bind *list ;
unsigned obso ;
{
register struct nr_bind *bp ;
struct nr_bind *best = NULLNRBIND ;
int maxqual = -1 ; /* negative infinity */
for (bp = list ; bp != NULLNRBIND ; bp = bp->next)
if ((int)bp->quality > maxqual)
if (obso || bp->obsocnt >= Obso_minbc) {
best = bp ;
maxqual = bp->quality ;
}
return best ;
}
/* Add a route to the net/rom routing table */
int
nr_routeadd(alias,dest,ifnum,quality,neighbor,permanent,record)
char *alias ; /* net/rom node alias, blank-padded and */
/* null-terminated */
struct ax25_addr *dest ; /* destination node callsign */
unsigned ifnum ; /* net/rom interface number */
unsigned quality ; /* route quality */
char *neighbor ; /* neighbor node + 2 digis (max) in arp format */
unsigned permanent ; /* 1 if route is permanent (hand-entered) */
unsigned record ; /* 1 if route is a "record route" */
{
struct nrroute_tab *rp ;
struct nr_bind *bp ;
struct nrnbr_tab *np ;
int16 rhash, nhash ;
struct ax25_addr ncall ;
/* See if a routing table entry exists for this destination */
if ((rp = find_nrroute(dest)) == NULLNRRTAB) {
if ((rp =
(struct nrroute_tab *)calloc(1,sizeof(struct nrroute_tab)))
== NULLNRRTAB)
return -1 ;
else { /* create a new route table entry */
strncpy(rp->alias,alias,6) ;
rp->call = *dest ;
rhash = nrhash(dest) ;
rp->next = Nrroute_tab[rhash] ;
if (rp->next != NULLNRRTAB)
rp->next->prev = rp ;
Nrroute_tab[rhash] = rp ; /* link at head of hash chain */
}
} else if (!record) {
strncpy(rp->alias,alias,6) ; /* update the alias */
}
/* See if an entry exists for this neighbor */
memcpy(ncall.call,neighbor,ALEN) ; /* no digis included */
ncall.ssid = neighbor[ALEN] ;
if ((np = find_nrnbr(&ncall,ifnum)) == NULLNTAB) {
if ((np =
(struct nrnbr_tab *)calloc(1,sizeof(struct nrnbr_tab)))
== NULLNTAB) {
if (rp->num_routes == 0) { /* we just added to table */
Nrroute_tab[rhash] = rp->next ;
free((char *)rp) ; /* so get rid of it */
}
return -1 ;
}
else { /* create a new neighbor entry */
memcpy(np->call,neighbor,3 * AXALEN) ;
np->iface = ifnum ;
nhash = nrhash(&ncall) ;
np->next = Nrnbr_tab[nhash] ;
if (np->next != NULLNTAB)
np->next->prev = np ;
Nrnbr_tab[nhash] = np ;
}
}
else if (permanent) { /* force this path to the neighbor */
memcpy(np->call,neighbor,3 * AXALEN) ;
}
/* See if there is a binding between the dest and neighbor */
if ((bp = find_binding(rp->routes,np)) == NULLNRBIND) {
if ((bp =
(struct nr_bind *)calloc(1,sizeof(struct nr_bind)))
== NULLNRBIND) {
if (rp->num_routes == 0) { /* we just added to table */
Nrroute_tab[rhash] = rp->next ;
free((char *)rp) ; /* so get rid of it */
}
if (np->refcnt == 0) { /* we just added it */
Nrnbr_tab[nhash] = np->next ;
free((char *)np) ;
}
return -1 ;
}
else { /* create a new binding and link it in */
bp->via = np ; /* goes via this neighbor */
bp->next = rp->routes ; /* link into binding chain */
if (bp->next != NULLNRBIND)
bp->next->prev = bp ;
rp->routes = bp ;
rp->num_routes++ ; /* bump route count */
np->refcnt++ ; /* bump neighbor ref count */
bp->quality = quality ;
bp->obsocnt = Obso_init ; /* use initial value */
if (permanent)
bp->flags |= NRB_PERMANENT ;
else if (record) /* notice permanent overrides record! */
bp->flags |= NRB_RECORDED ;
}
} else {
if (permanent) { /* permanent request trumps all */
bp->quality = quality ;
bp->obsocnt = Obso_init ;
bp->flags |= NRB_PERMANENT ;
bp->flags &= ~NRB_RECORDED ; /* perm is not recorded */
} else if (!(bp->flags & NRB_PERMANENT)) { /* not permanent */
if (record) { /* came from nr_route */
if (bp->flags & NRB_RECORDED) { /* no mod non-rec bindings */
bp->quality = quality ;
bp->obsocnt = Obso_init ; /* freshen recorded routes */
}
} else { /* came from a routing broadcast */
bp->quality = quality ;
bp->obsocnt = Obso_init ;
bp->flags &= ~NRB_RECORDED ; /* no longer a recorded route */
}
}
}
/* Now, check to see if we have too many bindings, and drop */
/* the worst if we do */
if (rp->num_routes > Nr_maxroutes) {
/* since find_worst never returns permanent entries, the */
/* limitation on number of routes is circumvented for */
/* permanent routes */
if ((bp = find_worst(rp->routes)) != NULLNRBIND) {
memcpy(ncall.call,bp->via->call,ALEN) ;
ncall.ssid = bp->via->call[ALEN] ;
nr_routedrop(dest,&ncall,bp->via->iface) ;
}
}
return 0 ;
}
/* Drop a route to dest via neighbor */
int
nr_routedrop(dest,neighbor,ifnum)
struct ax25_addr *dest, *neighbor ;
unsigned ifnum ;
{
register struct nrroute_tab *rp ;
register struct nrnbr_tab *np ;
register struct nr_bind *bp ;
if ((rp = find_nrroute(dest)) == NULLNRRTAB)
return -1 ;
if ((np = find_nrnbr(neighbor,ifnum)) == NULLNTAB)
return -1 ;
if ((bp = find_binding(rp->routes,np)) == NULLNRBIND)
return -1 ;
/* drop the binding first */
if (bp->next != NULLNRBIND)
bp->next->prev = bp->prev ;
if (bp->prev != NULLNRBIND)
bp->prev->next = bp->next ;
else
rp->routes = bp->next ;
free((char *)bp) ;
rp->num_routes-- ; /* decrement the number of bindings */
np->refcnt-- ; /* and the number of neighbor references */
/* now see if we should drop the route table entry */
if (rp->num_routes == 0) {
if (rp->next != NULLNRRTAB)
rp->next->prev = rp->prev ;
if (rp->prev != NULLNRRTAB)
rp->prev->next = rp->next ;
else
Nrroute_tab[nrhash(dest)] = rp->next ;
free((char *)rp) ;
}
/* and check to see if this neighbor can be dropped */
if (np->refcnt == 0) {
if (np->next != NULLNTAB)
np->next->prev = np->prev ;
if (np->prev != NULLNTAB)
np->prev->next = np->next ;
else
Nrnbr_tab[nrhash(neighbor)] = np->next ;
free((char *)np) ;
}
return 0 ;
}
#ifdef notused
/* Find the best neighbor for destination dest, in arp format */
static char *
nr_getroute(dest)
struct ax25_addr *dest ;
{
register struct nrroute_tab *rp ;
register struct nr_bind *bp ;
if ((rp = find_nrroute(dest)) == NULLNRRTAB)
return NULLCHAR ;
if ((bp = find_best(rp->routes,1)) == NULLNRBIND) /* shouldn't happen! */
return NULLCHAR ;
return bp->via->call ;
}
#endif /* notused */
/* Find an entry in the filter table */
static struct nrnf_tab *
find_nrnf(addr,ifnum)
register struct ax25_addr *addr ;
unsigned ifnum ;
{
int16 hashval ;
register struct nrnf_tab *fp ;
/* Find appropriate hash chain */
hashval = nrhash(addr) ;
/* search hash chain */
for (fp = Nrnf_tab[hashval] ; fp != NULLNRNFTAB ; fp = fp->next) {
if (addreq(&fp->neighbor,addr) && fp->iface == ifnum) {
return fp ;
}
}
return NULLNRNFTAB ;
}
/* Add an entry to the filter table. Return 0 on success,
* -1 on failure
*/
int
nr_nfadd(addr,ifnum)
struct ax25_addr *addr ;
unsigned ifnum ;
{
struct nrnf_tab *fp ;
int16 hashval ;
if (find_nrnf(addr,ifnum) != NULLNRNFTAB)
return 0 ; /* already there; it's a no-op */
if ((fp = (struct nrnf_tab *)calloc(1,sizeof(struct nrnf_tab)))
== NULLNRNFTAB)
return -1 ; /* no storage */
hashval = nrhash(addr) ;
fp->neighbor = *addr ;
fp->iface = ifnum ;
fp->next = Nrnf_tab[hashval] ;
if (fp->next != NULLNRNFTAB)
fp->next->prev = fp ;
Nrnf_tab[hashval] = fp ;
return 0 ;
}
/* Drop a neighbor from the filter table. Returns 0 on success, -1
* on failure.
*/
int
nr_nfdrop(addr,ifnum)
struct ax25_addr *addr ;
unsigned ifnum ;
{
struct nrnf_tab *fp ;
if ((fp = find_nrnf(addr,ifnum)) == NULLNRNFTAB)
return -1 ; /* not in the table */
if (fp->next != NULLNRNFTAB)
fp->next->prev = fp->prev ;
if (fp->prev != NULLNRNFTAB)
fp->prev->next = fp->next ;
else
Nrnf_tab[nrhash(addr)] = fp->next ;
free(fp) ;
return 0 ;
}